﻿using System.Net.Http.Headers;
using System.Text;
#if NET461
using System.Net.Http;
#endif

namespace OkFlurl
{
    public class FlurlForm
    {
        public FlurlForm()
        {

        }

        public FlurlForm(CancellationToken token)
        {
            Token = token;
        }

        public CancellationToken Token { get; set; } = default;

        internal long? UploadFileLength { get; set; } = 0;

        internal long UploadCurrSize { get; set; }

        internal double UploadPercent { get; set; }

        /// <summary>
        /// 上传缓冲大小
        /// </summary>
        public int UploadBufferSize { get; set; } = 4096;

        /// <summary>
        /// 下载缓冲大小
        /// </summary>
        public int DownloadBufferSize { get; set; } = 4096;

        /// <summary>
        /// 上传进度
        /// </summary>
        public FlurlProgress? UploadProgress { get; set; }

        /// <summary>
        /// 下载进度
        /// </summary>
        public FlurlProgress? DownloadProgress { get; set; }

        /// <summary>
        /// form表单
        /// </summary>
        internal MultipartFormDataContent Multipart { get; } = [];

        internal void ChangeUploadSize()
        {
            if (UploadProgress != null && UploadFileLength.HasValue && UploadFileLength.Value > 0)
            {
                var nowPercent = Math.Floor(UploadCurrSize * 1d / UploadFileLength.Value * 1d * 100);
                if (nowPercent > UploadPercent)
                {
                    UploadPercent = nowPercent;
                    UploadProgress.Change(UploadFileLength, UploadCurrSize, UploadPercent);
                }
            }
        }

        private void InitContent(string name, HttpContent content, string fileName, long? size)
        {
            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentException("name must not be empty", nameof(name));
            }

            content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
            {
                Name = name,
                FileName = fileName,
                FileNameStar = fileName,
                Size = size
            };

            Multipart.Add(content);
        }

        public void AddString(string name, string value, string contentType = null)
        {
            value ??= "";
            var content = new StringContent(value, Encoding.UTF8);
            content.Headers.Remove("Content-Type");
            if (contentType != null)
            {
                content.Headers.TryAddWithoutValidation("Content-Type", contentType);
            }
            InitContent(name, content, null, null);
        }

        public void AddStream(string name, Stream stream, string fileName, long? length = null, string contentType = null)
        {
            if (length.HasValue)
            {
                UploadFileLength += length.Value;
            }
            var content = new FlurlProgressStream(stream, this, fileName, length);
            if (contentType != null)
            {
                content.Headers.TryAddWithoutValidation("Content-Type", contentType);
            }

            InitContent(name, content, fileName, length);
        }

        public void AddFile(string name, string path, string fileName = null, string contentType = null)
        {
            fileName ??= Path.GetFileName(path);
            long? length = null;
            if (UploadProgress != null)
            {
                using var fs = new FileStream(path, FileMode.Open);
                length = fs.Length;
                UploadFileLength += length;
            }

            var content = new FlurlProgressFile(path, this, fileName);
            if (contentType != null)
            {
                content.Headers.TryAddWithoutValidation("Content-Type", contentType);
            }

            InitContent(name, content, fileName, length);
        }

        public void AddBytes(string name, byte[] data, string fileName = null)
        {
            var content = new ByteArrayContent(data);
            InitContent(name, content, fileName, data.Length);
        }

    }
}
